#include "Calc.h"
#include <Math.h>

inline char digitToChar(int digit)
{
	return digit < 10 ? digit+'0' : digit-10+'A';
}

template<typename T> StringRef floatToString(T val, T radix)
{
	RCharBuffer buf;

	if(val < T(0))
	{
		buf.pushBack('-');
		val = -val;
	}

	T frac = fmod(val, T(1));
	T sub = radix;
	while(val >= sub)
		sub *= radix;
	while(sub > T(1))
	{
		sub /= radix;
		T div = floor(val/sub);
		int digit = int(div);
		val -= div*sub;

		buf.pushBack(digitToChar(digit));
	}

	frac = val;

	buf.pushBack('.');

	while(frac > 0)
	{
		frac *= radix;
		T div = floor(frac);
		int digit = int(div);
		frac -= div;

		buf.pushBack(digitToChar(digit));
	}

	buf.pushBack(0);

	return StringRef::acquire(buf.getBufferAndReset());
}

float Calc::Registry::getVariable(StringRef variable)
{
	if(variable == "pi")
		return 3.1415926535897932384626433832795f;

	throw StringRef("Unknown variable");
}

float Calc::Registry::applyFunction(StringRef functionName, float parameter)
{
	throw StringRef("Functions are not supported yet");
}

Calc::Calc()
{
}

Calc::~Calc()
{
}

StringRef Calc::calculate(StringRef expr)
{
	try
	{
                return calculateThrowError(expr);
	}
	catch(StringRef errMsg)
	{
                return errMsg;
	}
}


StringRef Calc::calculateThrowError(StringRef expr) throw(StringRef)
{
        AutoDelete<FloatParser::Node> node = parser(*expr);

        StringRef result;

        return floatToString<float>(node->getValue(&registry), 10.0f);
}
